﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using HtmlAgilityPack;
using System.IO;

namespace GenerateZ80CodeCompletion
{
    class Program
    {
        static void Main(string[] args)
        {
            XDocument outputDocument = new XDocument();
            outputDocument.Add(new XElement("CodeCompletion"));
            string[] htmlFiles = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.html");
            foreach (string file in htmlFiles)
            {
                HtmlDocument thisDocument = new HtmlDocument();
                thisDocument.Load(file);
                HtmlNode bodyNode = thisDocument.DocumentNode.SelectSingleNode("html").SelectSingleNode("body");
                string name = "", actualValue = "", description = "", opcode = "", flags = "", tstates = "";
                string[] validParameters;
                int size = -1;
                int caretIndex = -1;
                foreach (HtmlNode node in bodyNode.ChildNodes)
                {
                    if (node.Name == "tt")
                    {
                        name = node.InnerText.ToLower().Replace("\r", "").Replace("\n", "");
                        Console.WriteLine(name);
                    }
                    else if (node.Name == "p")
                    {
                        try
                        {
                            name = node.SelectSingleNode("tt").InnerText.ToLower().Replace("\r", "").Replace("\n", "");
                            Console.WriteLine(name);
                        }
                        catch { }
                    }
                    if (node.Name == "table")
                    {
                        XElement thisElement = new XElement("code");
                        HtmlNode tbodyNode = node.SelectSingleNode("tbody");
                        if (tbodyNode == null)
                            tbodyNode = node;
                        try
                        {
                            description = tbodyNode.SelectSingleNode("tr").SelectSingleNode("td").InnerText.Replace("\r", "").Replace("\n", "").Replace("      ", " ");
                            actualValue = name.Replace("reg8", "").Replace("reg16", "").Replace("imm8", "").Replace("cc", "").Replace("ofs8", "").Replace("imm16", "").Replace("imm3", "").Replace("regindex", "").ToLower();
                            string[] caretStops = new string[]
                            {
                                "reg8",
                                "reg16",
                                "imm8",
                                "imm16",
                                "imm3",
                                "regindex",
                                "cc",
                                "ofs8",
                            };
                            foreach (string stop in caretStops)
                            {
                                caretIndex = name.IndexOf(stop);
                                if (caretIndex != -1)
                                    break;
                            }
                            if (caretIndex == -1)
                                caretIndex = actualValue.Length - 1;
                            flags = tbodyNode.SelectNodes("tr")[2].SelectSingleNode("td").InnerText.Replace("\r", "").Replace("\n", "").Replace("        ", "|").Replace("      ", "|");
                            try
                            {
                                tstates = tbodyNode.SelectNodes("tr")[3].SelectSingleNode("td").InnerText.Replace("\r", "").Replace("\n", "").Replace("      ", "|");
                            }
                            catch
                            {
                                tstates = tbodyNode.SelectNodes("tr")[2].SelectSingleNode("td").InnerText.Replace("\r", "").Replace("\n", "").Replace("      ", "|");
                            }
                            opcode = tbodyNode.SelectNodes("tr")[1].SelectSingleNode("td").SelectSingleNode("tt").InnerText.Replace("\r", "").Replace("\n", "");
                            string finishedCode = opcode.Replace(":", "").Replace(" ", "");
                            finishedCode = finishedCode.Replace("[imm8]", "00000000");
                            finishedCode = finishedCode.Replace("[imm16]", "0000000000000000");
                            finishedCode = finishedCode.Replace("[imm3]", "000");
                            finishedCode = finishedCode.Replace("[ofs8]", "00000000");
                            finishedCode = finishedCode.Replace("[regindex]", "00000000");
                            string regValue = "";
                            if (finishedCode.Contains("reg8") || finishedCode.Contains("reg16"))
                            {
                                try
                                {
                                    regValue = tbodyNode.SelectNodes("tr")[1].SelectSingleNode("td").SelectSingleNode("table").SelectSingleNode("tbody").SelectNodes("tr")[1].SelectNodes("td")[1].InnerText;
                                }
                                catch
                                {
                                    regValue = tbodyNode.SelectNodes("tr")[1].SelectSingleNode("td").SelectSingleNode("table").SelectNodes("tr")[1].SelectNodes("td")[1].InnerText;
                                }
                            }
                            finishedCode = finishedCode.Replace("[reg8]", regValue);
                            finishedCode = finishedCode.Replace("[reg16]", regValue);
                            size = finishedCode.Length / 8;
                        }
                        catch
                        {
                            try
                            {
                                tstates = tbodyNode.SelectNodes("tr")[2].SelectSingleNode("td").InnerText.Replace("\r", "").Replace("\n", "").Replace("      ", "|");
                            }
                            catch { }
                        }
                        finally
                        {
                            if (caretIndex != -1)
                                thisElement.SetAttributeValue("caretStop", caretIndex);
                            thisElement.SetAttributeValue("text", name);
                            if (actualValue != "")
                                thisElement.SetAttributeValue("actualValue", actualValue);
                            else
                                thisElement.SetAttributeValue("actualValue", name);
                            if (tstates != "")
                                thisElement.SetAttributeValue("tstates", tstates);
                            if (flags != "" && flags != tstates)
                                thisElement.SetAttributeValue("flags", flags);
                            if (description != "")
                                thisElement.SetValue(description);
                            if (opcode != "")
                                thisElement.SetAttributeValue("opcode", opcode);
                            if (size != -1)
                                thisElement.SetAttributeValue("size", size);
                            outputDocument.Root.Add(thisElement);
                            description = "";
                            flags = "";
                            caretIndex = -1;
                            tstates = "";
                            actualValue = "";
                            opcode = "";
                            size = -1;
                        }
                    }
                }
            }
            outputDocument.Save("z80InstructionSet.xml");
        }
    }
}
